
#include <sstream>
#include <iomanip>
#include <ctime>
#include "util.h"
#include "context.h"
#include "ActionBase.h"
#include "json.h"
#include "util.h"
#include "agencymgr.h"
#include "usermgr.h"
#include "Md5.h"


static const char* login_path = "/login";
class ActionGameLogin
{
public:
    static bool Init()
    {
        Ctx.msg_router.BindHttpHandle("get", login_path, std::bind(&ActionGameLogin::Handle, std::placeholders::_1, false));
        Ctx.msg_router.BindHttpHandle("post", login_path, std::bind(&ActionGameLogin::Handle, std::placeholders::_1, true));
        return true;
    }
    
public:
    static std::string formatDateAsYYMMD(const std::time_t& time = std::time(nullptr)) {

        // 获取当前系统时间  
        auto now = std::chrono::system_clock::now(); 
        // 将时间转换为time_t类型，以便转换为tm结构体,utf-4
        std::time_t now_c = std::chrono::system_clock::to_time_t(now - std::chrono::hours(4));
        // 获得utc时间
        std::tm* now_tm = std::gmtime(&now_c);
        // 格式化日期（注意这里没有使用前导零）  
        int year = now_tm->tm_year + 1900; // tm_year是从1900年开始的年份  
        int month = now_tm->tm_mon + 1;    // tm_mon是从0开始的月份  
        int day = now_tm->tm_mday;        // tm_mday是日期（1-31） 
    
        // 输出格式为YYMMDD，但DD没有前导零  
        std::ostringstream oss;  
        oss<< std::setfill('0') << std::setw(2) << year % 100  // 年份的后两位  
                << std::setw(2) << month                            // 月份  
                << day;                                            // 日期  

        // 使用put_time来格式化输出  
        //std::cout << "Current UTC-4 time: " << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S") << '\n';
        return oss.str();  
    }

    static std::string GetKeyG(const std::string& agency, const std::string& agency_key, std::int64_t balance)
    {
        std::string date_str = formatDateAsYYMMD();
        std::string keyG = date_str + agency + agency_key;
        log_debug("GetKey keyG =  %s", keyG.c_str());
        std::string sign_md5 = MD5(keyG).toStr();
        log_debug("GetKey after MD5 keyG =  %s", sign_md5.c_str());
        return sign_md5;
    }

    static void Handle(HttpData&& http_data, bool post)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        int err = 0;
        do
        {
            log_debug("Handle start, request_id:%d,ip:%s,target:%s,body:%s", http_data.request_id, http_data.ip.c_str(), http_data.target.c_str(), http_data.body.c_str());

            /*
            agency:xxxx, gameid:101, lang:en-US, balance:1000000
            */
            std::string agency;
            int gameid;
            std::string lang = "en-US";
            std::int64_t balance = 1000000000;
            std::string username = "";

            if (post)
            {
                Json::Value json;
                if (!CTools::FromStr(json, http_data.body))
                {
                    err = 1;
                    log_error("parser json failed, str::%s", http_data.body.c_str());
                    break;
                }
                if (!json.isMember("agency") || !json["agency"].isString())
                {
                    err = 2;
                    log_error("parser agency failed, str::%s", http_data.body.c_str());
                    break;
                }
                agency = json["agency"].asString();
                if (!json.isMember("gameid") || !json["gameid"].isInt())
                {
                    err = 3;
                    log_error("parser gameid failed, str::%s", http_data.body.c_str());
                    break;
                }
                gameid = json["gameid"].asInt();

                if (json.isMember("lang") && json["lang"].isString())
                {
                    lang = json["lang"].asString();
                }
                if (json.isMember("balance") && json["balance"].isDouble())
                {
                    balance = json["balance"].asDouble() * 1000;
                }
                if (json.isMember("username") && json["username"].isString())
                {
                    username = json["username"].asString();
                }
            }
            else
            {
                if (http_data.params.end() == http_data.params.find("agency")) { log_error("param error, %s", http_data.target.c_str()); err = 1; break; }
                if (http_data.params.end() == http_data.params.find("gameid")) { log_error("param error, %s", http_data.target.c_str()); err = 2; break; } 
                agency = http_data.params["agency"];
                gameid = ::atol(http_data.params["gameid"].c_str());
                if (http_data.params.end() != http_data.params.find("lang")) 
                {
                    lang = http_data.params["lang"];
                }
                if (http_data.params.end() != http_data.params.find("balance")) 
                {
                    balance = ::atoll(http_data.params["balance"].c_str());
                }
                if (http_data.params.end() != http_data.params.find("username")) 
                {
                    username = http_data.params["username"].c_str();
                }
            }
            
            stAgency* st_agency = AgencyMgr::Instance()->Get(agency);
            if (st_agency == nullptr)
            {
                 err = 4;
                 log_error("agency not found, agency::%s", agency.c_str());
                 break;
            }
            
            stUser* st_user = nullptr;
            if (username.empty())
            {
                st_user = UserMgr::Instance()->GenUser(st_agency->name, st_agency->currency, balance);
                if (st_user == nullptr)
                {
                     err = 5;
                     log_error("GenUser failed, agency::%s,currency:%s,balance:%lld", st_agency->name.c_str(), st_agency->currency.c_str(), balance);
                     break;
                }
            }
            else
            {
                st_user = UserMgr::Instance()->Get(username);
                if (st_user == nullptr)
                {
                    //  err = 12;
                    //  log_error("get user failed, username:%s, agency:%s,currency:%s,balance:%lld", username.c_str(), st_agency->name.c_str(), st_agency->currency.c_str(), balance);
                    //  break;
                    st_user = UserMgr::Instance()->GenUser(st_agency->name, st_agency->currency, balance, username);
                }
                if (st_user->agency.compare(agency) != 0)
                {
                    err = 13;
                    log_error("agency match failed, username:%s, agency:%s,currency:%s,balance:%lld", username.c_str(), st_agency->name.c_str(), st_agency->currency.c_str(), balance);
                    break;
                }
                st_user->balance = balance;
            }

            std::string reqStr;
            std::string token = UsernameToToken(st_user->username);
            Json::Value req_json;
            req_json["AgentId"] = st_agency->name;

            std::stringstream queryStr;
            queryStr << "Token=" << token 
                    << "&GameId=" << gameid 
                    << "&Lang=" << lang 
                    << "&AgentId=" << st_agency->name;
            std::string queryMd5 = queryStr.str() + GetKeyG(st_agency->name, st_agency->key, balance);
            std::string md5Str = MD5(queryMd5).toStr();
            std::string randomText1 = "******";
            std::string randomText2 = "******";
            std::string key = randomText1 + md5Str + randomText2;
            reqStr = queryStr.str() + "&Key=" + key;

            std::string url = st_agency->api;
            if (0 != url.substr(0,4).compare("http"))
            {
                #ifdef CLIENT_HTTPS
                        url += "https://";
                #else
                        url += "http://";
                #endif
            }
            url += "/singleWallet/LoginWithoutRedirect";
            url += "?" + reqStr;

            std::map<std::string,std::string> heads;
            //heads["Content-Type"] = "application/x-www-form-urlencoded";

            log_debug("post req, url:%s", url.c_str());
            std::uint32_t callback_id = 0;
            if (!Ctx.msg_router.sendHttpGET(url, "", heads, callback_id) || (callback_id == 0))
            {
                err = 6;
                log_error("sendHttpGET failed, url:%s, callback_id:%u", url.c_str(), callback_id);
                break;
            }

            // 添加回调监听
            Ctx.msg_router.AddCurlEvent(callback_id, [request_id=http_data.request_id, url] (std::string& body, bool is_ok){
                log_debug("request_id:%d, url:%s, body:%s, is_ok:%d", request_id, url.c_str(), body.c_str(), is_ok);
                int err = 0;
                std::string lauch_url = "";
                do
                {
                    Json::Value res_json;
                    if (!is_ok)
                    {
                        err = 7;
                        log_error("is_ok is false");
                        break;
                    }
                    {
                        Json::Reader reader;
                        if (!reader.parse(body, res_json))
                        {
                            err = 8;
                            log_error("paser post result json failed body = %s", body.c_str());
                            break;
                        }
                        if (!res_json.isMember("ErrorCode") || !res_json["ErrorCode"].isNumeric())
                        {
                            err = 9;
                            log_error("json no member 'ErrorCode' or type error body = %s", body.c_str());
                            break;
                        }
                        if (res_json["ErrorCode"].asInt() != 0)
                        {
                            err = 10;
                            log_error("json.ErrorCode asInt() != 0 body = %s", body.c_str());
                            break;
                        }
                        
                        if (!res_json.isMember("Data") || !res_json["Data"].isString())
                        {
                            err = 11;
                            log_error("json no member 'Data' or type error body = %s", body.c_str());
                            break;
                        }
                        lauch_url = res_json["Data"].asString();
                    }
                } while (false);
                
                log_debug("Handle over, id:%d, err:%d, str:%s", request_id, err, lauch_url.c_str());
                ResponseHttp(request_id, lauch_url);
            });

            return;
        } while (false);
        log_debug("Handle over, id:%d, err:%d, str:%s", http_data.request_id, err, http_data.body.c_str());
        ResponseHttp(http_data.request_id, "");
    }

};

static bool __init__ = ActionGameLogin::Init();

